using System;
using System.Collections.Generic;
using System.Text;
using Castle.ActiveRecord;
using System.Security.Cryptography;

using Castle.ActiveRecord.Framework.Validators;

namespace ElevatorSpeeches.Framework
{    
    [ActiveRecord("[User]")]
    [Serializable]
    public class User : EntityBase<User>
    {
        [Property]
        [ValidateIsUnique]
        [ValidateNotEmpty("UserName is Required.")]
        public string Name { get; set; }
        
        [Property]
        [ValidateEmail("Valid Email is Required.")]
        public string Email { get; set; }
                
        [Property]
        public string Url { get; set; }

        private string _Password;        
        public string Password
        {
            get
            {
                return _Password;
            }
            set
            {
                if (_PasswordConfirmation == value)
                    SetPasswordHash();
                _Password = value;
            }
        }

        private string _PasswordConfirmation;          
        public string PasswordConfirmation
        {
            get
            {
                return _PasswordConfirmation;
            }
            set
            {
                if (_Password == value)
                    SetPasswordHash();
                _PasswordConfirmation = value;
            }
        }

        private byte[] _PasswordHash;
        [Property]
        [ValidateNotEmpty]
        public byte[] PasswordHash
        {
            get
            {
                return _PasswordHash;
            }
            set
            {
                _PasswordHash = value;
            }
        }

        public void SetPasswordHash()
        {
            PasswordHash = _GetHash(Password);
        }

        private byte[] _GetHash(string value)
        {
            SHA1 sha1 = SHA1.Create();
            return sha1.ComputeHash(UnicodeEncoding.UTF8.GetBytes(value));
        }

 
        [Property]
        public string ImageUrl { get; set; }

        
        [Property]
        public DateTime SignUpDate { get; set; }

        public override bool IsValid()
        {            
            if (IsNew() && String.IsNullOrEmpty(Password))
            {
                CustomErrorMessages.Add("Password is Required.");
            }
            else
            {
                if (Password != PasswordConfirmation)
                    CustomErrorMessages.Add("Password and Password Confirmation do not Match.");
            }

            return base.IsValid() && CustomErrorMessages.Count == 0;
        }

        public bool IsPasswordCorrect(string password)
        {            
            byte[] newHash = _GetHash(password);

            if (newHash.Length != PasswordHash.Length) return false;

            for (int x = 0; x < newHash.Length; x++)
            {
                if (newHash[x] != PasswordHash[x]) return false;
            }

            return true;
        }

        public static User GetAuthenticatedUser(string userName, string password)
        {
            User rv = GetByUserName(userName);

            if (rv == null)
                throw new ArgumentException("No such user exists");

            if (!rv.IsPasswordCorrect(password))
                throw new ArgumentException("Invalid Password");

            return rv;
        }

        public static User GetByUserName(string userName)
        {
            return User.FindOne(new NHibernate.Expression.EqExpression("Name", userName));
        }

        public override void Save()
        {
            if (ID < 1)
                SignUpDate = DateTime.Now;

            base.Save();
        }

		public static User Login(string userName, string password)
		{
			User user = User.FindOne(new NHibernate.Expression.EqExpression("Name", userName));
			if (user == null || !user.IsPasswordCorrect(password))
				return null;										
			else
				return user;				
		}
    }
}